/**
 * gntodo.c
 *
 * Copyright (C) 2007 Sadrul Habib Chowdhury <sadrul@pidgin.im>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include <gnt.h>
#include <gntbox.h>
#include <gntbutton.h>
#include <gntentry.h>
#include <gntlabel.h>
#include <gntline.h>
#include <gntstyle.h>
#include <gnttextview.h>
#include <gntwindow.h>

#include "task.h"

/**
 * The global todo window.
 */
struct
{
	GntWidget *win;
	GntWidget *tasks;
	GntWidget *filter;
	GntWidget *name;
	/**
	 * A task editor window.
	 */
	struct {
		GntWidget *name;
		GntWidget *details;
		GntWidget *tags;
		GntWidget *edit;
		gboolean dirty;    /* Has the current task been changed? Unused, now. */
	} editor;
} todo_window;

static GntWidget*
gnt_label_new_fixed(const char *text)
{
	GntWidget *wid = gnt_label_new(text);
	GNT_WIDGET_UNSET_FLAGS(wid, GNT_WIDGET_GROW_X);
	return wid;
}

static char *
tags_to_string(GList *list)
{
	GString *string = g_string_new(NULL);
	while (list) {
		GTag *tag = list->data;
		list = list->next;
		string = g_string_append(string, tag->name);
		if (list)
			string = g_string_append(string, ", ");
	}
	return g_string_free(string, FALSE);
}

static void
update_suggest_lists()
{
	const GList *iter = gt_tags_get_all();
	for (; iter; iter = iter->next) {
		GTag *tag = iter->data;
		gnt_entry_add_suggest(GNT_ENTRY(todo_window.filter), tag->name);
		gnt_entry_add_suggest(GNT_ENTRY(todo_window.editor.tags), tag->name);
	}
}

static void
add_task_to_list(GTask *task)
{
	g_return_if_fail(task);

	gnt_tree_add_row_after(GNT_TREE(todo_window.tasks), task,
			gnt_tree_create_row(GNT_TREE(todo_window.tasks), task->name),
			NULL, NULL);
}

static void
setup_widget_size()
{
	int maxy = getmaxy(stdscr), maxx = getmaxx(stdscr);
	int taskwidth = MAX(30, maxx / 3);

	gnt_widget_set_size(todo_window.tasks, taskwidth, maxy);
	gnt_widget_set_size(todo_window.editor.details, maxx - taskwidth - 5, maxy);
}

/* {{{ Task editor */

static void
task_editor_save_cb(GntWidget *widget, gpointer data)
{
	GTask *task = gnt_tree_get_selection_data(GNT_TREE(todo_window.tasks));
	const char *text = gnt_entry_get_text(GNT_ENTRY(todo_window.editor.tags));

	while (task->tags)
		gt_task_remove_tag(task, task->tags->data);
	gt_task_add_tags_from_string(task, text);

	g_free(task->details);
	task->details = g_strdup(GNT_TEXT_VIEW(todo_window.editor.details)->string->str);

	gt_tasks_save(FALSE);
	update_suggest_lists();
}

static void
task_editor_edit_cb(GntWidget *widget, gpointer null)
{
	char *key = gnt_style_get_from_name("editor", "key");
	gnt_widget_key_pressed(todo_window.win, key ? key : "\033" "e");
	g_free(key);
}

/* }}} Task editor */

/* {{{ Signal handlers on the widgets */

static void
add_cb(GntWidget *button, gpointer null)
{
	const char *text = gnt_entry_get_text(GNT_ENTRY(todo_window.name));
	GTask *task;

	if (!text || !*text) {
		gnt_box_give_focus_to_child(GNT_BOX(todo_window.win), todo_window.name);
		return;
	}

	task = gt_task_new(text, NULL);
	gt_task_add_tags_from_string(task, gnt_entry_get_text(GNT_ENTRY(todo_window.filter)));

	add_task_to_list(task);
	gnt_tree_set_selected(GNT_TREE(todo_window.tasks), task);
	gnt_entry_set_text(GNT_ENTRY(todo_window.name), NULL);
	gnt_box_give_focus_to_child(GNT_BOX(todo_window.win), todo_window.editor.edit);
	gt_tasks_save(FALSE);
}

static void
del_cb(GntWidget *button, gpointer null)
{
	GTask *task = gnt_tree_get_selection_data(GNT_TREE(todo_window.tasks));
	gnt_tree_remove(GNT_TREE(todo_window.tasks), task);
	gt_task_delete(task);
	gt_tasks_save(FALSE);
}

static gboolean
tag_cb(GntWidget *entry, const char *text, gpointer null)
{
	const GList *iter;
	char **tags;
	int i;

	if (text[0] != '\r')
		return FALSE;
	tags = g_strsplit(gnt_entry_get_text(GNT_ENTRY(entry)), ",", -1);
	for (i = 0; tags[i]; i++)
		g_strstrip(tags[i]);

	gnt_tree_remove_all(GNT_TREE(todo_window.tasks));
	for (iter = gt_tasks_get_all(); iter; iter = iter->next) {
		for (i = 0; tags[i]; i++)
			if (gt_task_is_tagged(iter->data, tags[i]))
				break;
		if (!tags[i] && i > 0)
			continue;
		add_task_to_list(iter->data);
	}
	gnt_widget_draw(todo_window.tasks);

	g_strfreev(tags);
	return TRUE;
}

static gboolean
mark_task_dirty(GntWidget *entry, gpointer null)
{
	todo_window.editor.dirty = TRUE;
	return FALSE;
}

static void
selection_changed_cb(GntWidget *tree, gpointer old, gpointer current, gpointer null)
{
	GTask *task = current;
	char *text;

	gnt_label_set_text(GNT_LABEL(todo_window.editor.name), "");
	gnt_entry_set_text(GNT_ENTRY(todo_window.editor.tags), NULL);
	gnt_text_view_clear(GNT_TEXT_VIEW(todo_window.editor.details));
	if (!task)
		return;

	gnt_label_set_text(GNT_LABEL(todo_window.editor.name), task->name);

	text = tags_to_string(task->tags);
	gnt_entry_set_text(GNT_ENTRY(todo_window.editor.tags), text);
	g_free(text);

	gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(todo_window.editor.details), task->details, GNT_TEXT_FLAG_NORMAL);
	gnt_text_view_scroll(GNT_TEXT_VIEW(todo_window.editor.details), 0);

	todo_window.editor.dirty = FALSE;
}

/* }}} Signal handlers on the widgets */

static void
setup_todo_window()
{
	GntWidget *win, *tree, *tag, *details, *name, *add, *edit, *vbox, *hbox, *del;
	GntWidget *tags, *save, *edname;

	if (todo_window.win) {
		gnt_window_present(todo_window.win);
		return;
	}

	/* Setup the window and the layout */
	win = gnt_hwindow_new(FALSE);
	gnt_box_set_title(GNT_BOX(win), "GNTodo");
	gnt_box_set_fill(GNT_BOX(win), TRUE);
	gnt_box_set_alignment(GNT_BOX(win), GNT_ALIGN_TOP);

	vbox = gnt_vbox_new(FALSE);
	gnt_box_set_pad(GNT_BOX(vbox), 0);
	gnt_box_set_fill(GNT_BOX(vbox), TRUE);
	gnt_box_set_title(GNT_BOX(vbox), "Task List");
	gnt_box_set_alignment(GNT_BOX(vbox), GNT_ALIGN_MID);
	GNT_WIDGET_UNSET_FLAGS(vbox, GNT_WIDGET_NO_BORDER);

	gnt_box_add_widget(GNT_BOX(win), vbox);

	hbox = gnt_hbox_new(FALSE);
	gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new_fixed("Filter tags"));
	gnt_box_add_widget(GNT_BOX(hbox), tag = gnt_entry_new(NULL));
	gnt_box_add_widget(GNT_BOX(vbox), hbox);

	gnt_box_add_widget(GNT_BOX(vbox), tree = gnt_tree_new());
	gnt_box_add_widget(GNT_BOX(vbox), name = gnt_entry_new(NULL));

	hbox = gnt_hbox_new(FALSE);
	gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID);
	gnt_box_set_fill(GNT_BOX(hbox), FALSE);
	gnt_box_add_widget(GNT_BOX(hbox), add = gnt_button_new("Add"));
	gnt_box_add_widget(GNT_BOX(hbox), del = gnt_button_new("Delete"));
	gnt_box_add_widget(GNT_BOX(vbox), hbox);

	/* The editor on the right */
	vbox = gnt_vbox_new(FALSE);
	gnt_box_set_pad(GNT_BOX(vbox), 0);
	gnt_box_set_fill(GNT_BOX(vbox), TRUE);
	gnt_box_set_title(GNT_BOX(vbox), "Edit Task");
	gnt_box_set_alignment(GNT_BOX(vbox), GNT_ALIGN_MID);
	GNT_WIDGET_UNSET_FLAGS(vbox, GNT_WIDGET_NO_BORDER);

	hbox = gnt_hbox_new(FALSE);
	gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new_fixed("Name:"));
	gnt_box_add_widget(GNT_BOX(hbox), edname = gnt_label_new_with_format("", GNT_TEXT_FLAG_BOLD));
	gnt_box_add_widget(GNT_BOX(vbox), hbox);

	gnt_box_add_widget(GNT_BOX(vbox), details = gnt_text_view_new());

	hbox = gnt_hbox_new(FALSE);
	gnt_box_set_fill(GNT_BOX(hbox), FALSE);
	gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID);
	gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new_fixed("Tags"));
	gnt_box_add_widget(GNT_BOX(hbox), tags = gnt_entry_new(NULL));
	gnt_box_add_widget(GNT_BOX(vbox), hbox);

	hbox = gnt_hbox_new(FALSE);
	gnt_box_set_fill(GNT_BOX(hbox), FALSE);
	gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID);
	gnt_box_add_widget(GNT_BOX(hbox), edit = gnt_button_new("Edit Details"));
	gnt_box_add_widget(GNT_BOX(hbox), save = gnt_button_new("Save"));
	gnt_box_add_widget(GNT_BOX(vbox), hbox);

	gnt_box_add_widget(GNT_BOX(win), vbox);

	/* Setup the global struct for the window */
	todo_window.win = win;
	todo_window.tasks = tree;
	todo_window.filter = tag;
	todo_window.name = name;
	todo_window.editor.details = details;
	todo_window.editor.tags = tags;
	todo_window.editor.edit = edit;
	todo_window.editor.name = edname;

	/* Setup signal handlers */
	g_signal_connect(G_OBJECT(add), "activate", G_CALLBACK(add_cb), NULL);
	g_signal_connect(G_OBJECT(del), "activate", G_CALLBACK(del_cb), NULL);
	g_signal_connect(G_OBJECT(tag), "key_pressed", G_CALLBACK(tag_cb), NULL);
	g_signal_connect(G_OBJECT(tree), "selection-changed", G_CALLBACK(selection_changed_cb), NULL);
	g_signal_connect(G_OBJECT(save), "activate", G_CALLBACK(task_editor_save_cb), NULL);
	g_signal_connect(G_OBJECT(edit), "activate", G_CALLBACK(task_editor_edit_cb), NULL);
	g_signal_connect(G_OBJECT(tags), "key_pressed", G_CALLBACK(mark_task_dirty), NULL);
	g_signal_connect_swapped(G_OBJECT(win), "destroy", G_CALLBACK(g_nullify_pointer), &todo_window.win);
	gnt_text_view_attach_editor_widget(GNT_TEXT_VIEW(details), win);
	gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(details), edit);
	gnt_tree_set_compare_func(GNT_TREE(tree), gt_task_compare);

	/* Populate the tasklist */
	g_list_foreach((GList *)gt_tasks_get_all(), (GFunc)add_task_to_list, NULL);
	update_suggest_lists();

	setup_widget_size();

	gnt_widget_show(win);

	GNT_WIDGET_UNSET_FLAGS(tree, GNT_WIDGET_GROW_X);
	GNT_WIDGET_UNSET_FLAGS(tag, GNT_WIDGET_GROW_X);
	GNT_WIDGET_UNSET_FLAGS(add, GNT_WIDGET_GROW_X);
	GNT_WIDGET_UNSET_FLAGS(del, GNT_WIDGET_GROW_X);
	GNT_WIDGET_UNSET_FLAGS(name, GNT_WIDGET_GROW_X);
}

gboolean gnt_start(int *argc, char **argv[])
{
	setup_todo_window();

	gnt_register_action("Todo Window", setup_todo_window);

	return TRUE;
}

gboolean gnt_preinit(int *argc, char **argv[])
{
	char *userdir = NULL;
	GOptionEntry entries[] = {
		{"config", 'c', G_OPTION_FLAG_FILENAME | G_OPTION_FLAG_OPTIONAL_ARG,
			G_OPTION_ARG_FILENAME, &userdir, "Location of the configuration files", NULL},
		{NULL},
	};
	GOptionContext *context = g_option_context_new("- options for GNTodo");
	g_option_context_add_main_entries(context, entries, NULL);
	g_option_context_parse(context, argc, argv, NULL);
	g_option_context_free(context);

	if (userdir == NULL)
		userdir = g_build_filename(g_get_home_dir(), ".gntodo", NULL);

	gt_tasks_set_homedir(userdir);
	gt_tasks_load();
	g_free(userdir);

	return TRUE;
}

void gnt_stop()
{
	gt_tasks_save(TRUE);
}

int main(int argc, char *argv[])
{
	g_set_prgname("gntodo");
	gnt_preinit(&argc, &argv);
	gnt_init();
	gnt_start(&argc, &argv);
	gnt_main();
	gnt_stop();
	gnt_quit();
	return 0;
}

